/*
 *  This file is part of LifeBudget - Copyright 2010 Clifton Eaton
 *  ------------------------------------------------------------------
 *  LifeBudget is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  LifeBudget is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with LifeBudget.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.lifebudget.app.client.mvc.view;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.lifebudget.app.client.events.AppEvents;
import org.lifebudget.app.client.misc.NumberFormatter;
import org.lifebudget.app.client.mvc.model.BMF;
import org.lifebudget.app.client.mvc.model.Category;
import org.lifebudget.app.client.mvc.model.PaycheckCalculator;
import org.lifebudget.app.client.mvc.model.Transaction;
import org.lifebudget.app.client.mvc.model.TransactionData;
import org.lifebudget.app.client.mvc.model.Transaction.TransactionType;

import com.extjs.gxt.ui.client.Registry;
import com.extjs.gxt.ui.client.Style.HorizontalAlignment;
import com.extjs.gxt.ui.client.Style.Orientation;
import com.extjs.gxt.ui.client.Style.SelectionMode;
import com.extjs.gxt.ui.client.binding.Converter;
import com.extjs.gxt.ui.client.binding.FieldBinding;
import com.extjs.gxt.ui.client.binding.FormBinding;
import com.extjs.gxt.ui.client.data.BeanModel;
import com.extjs.gxt.ui.client.data.ModelData;
import com.extjs.gxt.ui.client.event.ButtonEvent;
import com.extjs.gxt.ui.client.event.Events;
import com.extjs.gxt.ui.client.event.FieldEvent;
import com.extjs.gxt.ui.client.event.Listener;
import com.extjs.gxt.ui.client.event.MessageBoxEvent;
import com.extjs.gxt.ui.client.event.SelectionChangedEvent;
import com.extjs.gxt.ui.client.event.SelectionListener;
import com.extjs.gxt.ui.client.mvc.AppEvent;
import com.extjs.gxt.ui.client.mvc.Controller;
import com.extjs.gxt.ui.client.mvc.Dispatcher;
import com.extjs.gxt.ui.client.mvc.View;
import com.extjs.gxt.ui.client.store.ListStore;
import com.extjs.gxt.ui.client.store.Record;
import com.extjs.gxt.ui.client.store.StoreEvent;
import com.extjs.gxt.ui.client.store.StoreListener;
import com.extjs.gxt.ui.client.widget.ContentPanel;
import com.extjs.gxt.ui.client.widget.Dialog;
import com.extjs.gxt.ui.client.widget.LayoutContainer;
import com.extjs.gxt.ui.client.widget.MessageBox;
import com.extjs.gxt.ui.client.widget.TabItem;
import com.extjs.gxt.ui.client.widget.Text;
import com.extjs.gxt.ui.client.widget.button.Button;
import com.extjs.gxt.ui.client.widget.form.ComboBox;
import com.extjs.gxt.ui.client.widget.form.DateField;
import com.extjs.gxt.ui.client.widget.form.FieldSet;
import com.extjs.gxt.ui.client.widget.form.FormPanel;
import com.extjs.gxt.ui.client.widget.form.NumberField;
import com.extjs.gxt.ui.client.widget.form.SimpleComboBox;
import com.extjs.gxt.ui.client.widget.form.TextField;
import com.extjs.gxt.ui.client.widget.form.ComboBox.TriggerAction;
import com.extjs.gxt.ui.client.widget.form.FormPanel.LabelAlign;
import com.extjs.gxt.ui.client.widget.grid.CellEditor;
import com.extjs.gxt.ui.client.widget.grid.ColumnConfig;
import com.extjs.gxt.ui.client.widget.grid.ColumnModel;
import com.extjs.gxt.ui.client.widget.grid.Grid;
import com.extjs.gxt.ui.client.widget.layout.FitLayout;
import com.extjs.gxt.ui.client.widget.layout.RowData;
import com.extjs.gxt.ui.client.widget.layout.RowLayout;
import com.extjs.gxt.ui.client.widget.toolbar.ToolBar;
import com.google.gwt.core.client.GWT;
import com.google.gwt.i18n.client.DateTimeFormat;

/**
 * The Class TransactionJournalView contains the controls for CRUD operations
 * on Transactions.  It also listens for, and provides refresh notifications 
 * for the overview tab.
 */
public class TransactionJournalView extends View {

	/** The transactions tab. */
	private TabItem transactionsTab;
	
	/** The container. */
	private ContentPanel container;
	
	/** The transaction grid. */
	private Grid<BeanModel> transactionGrid;
	
	/** The description column. */
	private ColumnConfig descriptionColumn;
	
	/** The amount column. */
	private ColumnConfig amountColumn;
	
	/** The date column. */
	private ColumnConfig dateColumn;
	
	/** The selected transaction. */
	private Transaction selectedTransaction;

	/** The transaction store. */
	private ListStore<BeanModel> transactionStore;

	/** The add transaction button. */
	private Button addTransactionButton;

	/** The remove transactions button. */
	private Button removeTransactionsButton;

	/** The category combo box. */
	private ComboBox<BeanModel> categoryComboBox;

	/** The categories store. */
	private ListStore<BeanModel> categoriesStore;

	/** The paycheck store. */
	private ListStore<PaycheckCalculator> paycheckStore;

	/** The paycheck combo box. */
	private ComboBox<PaycheckCalculator> paycheckComboBox;

	/** The transaction form. */
	private FormPanel transactionForm;

	/** The description field. */
	private TextField<String> descriptionField;

	/** The date field. */
	private DateField dateField;

	/** The amount field. */
	private NumberField amountField;

	/** The transaction details form bindings. */
	private FormBinding transactionDetailsFormBindings;

	/**
	 * Instantiates a new transaction journal view.
	 *
	 * @param controller the controller
	 */
	public TransactionJournalView(Controller controller) {
		super(controller);

	}

	/* (non-Javadoc)
	 * @see com.extjs.gxt.ui.client.mvc.View#initialize()
	 */
	public void initialize() {

	}

	/**
	 * Handles the <code>Init</code> event, adding all of the 
	 * Transaction related components to the registered transactions tab.
	 *
	 * @param event the event
	 */
	public void initUI(AppEvent event) {
		LayoutContainer center = (LayoutContainer) Registry.get(AppView.CENTER_PANEL);
		// get the reference to the Transactions Tab
		transactionsTab = (TabItem) Registry.get(TabView.TRANSACTIONS_TAB);

		// unpack the event data
		TransactionData td = (TransactionData) event.getData();
		initializeStores(td);

		createTransactionPanel();
		transactionsTab.add(container);
		center.layout();
	}

	/**
	 * Utility method to create the transaction panel.
	 */
	private void createTransactionPanel() {
		container = new ContentPanel();
		container.setLayout(new FitLayout());

		container.setHeaderVisible(false);
		container.setFrame(false);

		RowLayout rLayout = new RowLayout(Orientation.HORIZONTAL);
		LayoutContainer rowWidget = new LayoutContainer(rLayout);
		createTransactionGrid();

		rowWidget.add(transactionGrid, new RowData(.59, 1));
		rowWidget.add(new Text(), new RowData(.01, 1));

		createTransactionForm();
		FieldSet fs = new FieldSet();
		fs.add(transactionForm);
		fs.setHeading("Transaction Details");
		rowWidget.add(fs, new RowData(.4, 1));

		container.add(rowWidget);

		// Setup top toolbar
		ToolBar toolBar = createTransactionToolBar();

		container.setTopComponent(toolBar);
		container.setButtonAlign(HorizontalAlignment.CENTER);
		container.addButton(new Button("Reset", new SelectionListener<ButtonEvent>() {

			@Override
			public void componentSelected(ButtonEvent ce) {
				handleResetButtonClicked();
			}

		}));

		container.addButton(new Button("Save", new SelectionListener<ButtonEvent>() {

			@Override
			public void componentSelected(ButtonEvent ce) {
				handleCommitButtonClicked();
			}

			private void handleCommitButtonClicked() {
				transactionStore.commitChanges();
			}
		}));
	}

	/**
	 * Handle reset button clicked.
	 */
	private void handleResetButtonClicked() {
		List<BeanModel> models = transactionStore.getModels();
		// remove all of the transactions that were "added" but not committed
		for (BeanModel beanModel : models) {
			if ((Long) beanModel.get("id") == 0) {
				transactionStore.remove(beanModel);
			}
		}
		transactionStore.rejectChanges();
	}

	/**
	 * Creates the transaction tool bar.
	 *
	 * @return the tool bar
	 */
	private ToolBar createTransactionToolBar() {
		ToolBar toolBar = new ToolBar();
		addTransactionButton = new Button("Add Transaction");
		addTransactionButton.addSelectionListener(new SelectionListener<ButtonEvent>() {

			@Override
			public void componentSelected(ButtonEvent ce) {
				handleAddTransactionButtonClicked();

			}

		});
		removeTransactionsButton = new Button("Remove Selected");
		removeTransactionsButton.addSelectionListener(new SelectionListener<ButtonEvent>() {

			@Override
			public void componentSelected(ButtonEvent ce) {
				handleRemoveTransactionsButtonClicked(ce);
			}

		});

		if (transactionStore.getModels().isEmpty()) {
			removeTransactionsButton.disable();
		}

		toolBar.add(addTransactionButton);
		toolBar.add(removeTransactionsButton);
		return toolBar;
	}

	/**
	 * Handle remove transactions button clicked.
	 *
	 * @param ce the button event
	 */
	protected void handleRemoveTransactionsButtonClicked(ButtonEvent ce) {
		final Transaction t = (Transaction) transactionGrid.getSelectionModel().getSelectedItem().getBean();
		String msg = "Are you sure you wish to permanently delete " + "the transaction \"" + t.getDescription() + "\"?";
		MessageBox.confirm("Delete Transaction?", msg, new Listener<MessageBoxEvent>() {

			@Override
			public void handleEvent(MessageBoxEvent be) {
				Button button = be.getButtonClicked();

				if (button.getText().equals("Yes")) {
					BeanModel bm = transactionGrid.getSelectionModel().getSelectedItem();
					transactionStore.remove(bm);
					if ((Long) bm.get("id") != 0) {
						fireEvent(new AppEvent(AppEvents.TransactionRemoved, t));
					}
				}

			}
		});
	}

	/**
	 * Handle add transaction button clicked.
	 */
	private void handleAddTransactionButtonClicked() {
		// popup message box to prompt for name
		final Dialog box = new Dialog();

		box.setButtons(MessageBox.OKCANCEL);
		box.setButtonAlign(HorizontalAlignment.CENTER);
		box.setHeading("New Transaction");
		box.setBodyBorder(false);
		// box.setHideOnButtonClick(true);
		box.setModal(true);

		FormPanel formPanel = new FormPanel();
		formPanel.setLabelAlign(LabelAlign.TOP);
		formPanel.setBorders(false);
		formPanel.setHeaderVisible(false);
		formPanel.setBodyBorder(false);
		final SimpleComboBox<TransactionType> typeCombo = new SimpleComboBox<TransactionType>();
		typeCombo.add(TransactionType.Categorized);
		typeCombo.add(TransactionType.Paycheck);

		typeCombo.setFieldLabel("Please choose a transaction type");
		typeCombo.setAllowBlank(false);
		typeCombo.setTypeAhead(false);
		typeCombo.setEditable(false);
		typeCombo.setForceSelection(true);
		typeCombo.setTriggerAction(TriggerAction.ALL);

		formPanel.add(typeCombo);
		box.add(formPanel);
		box.getButtonById("ok").addSelectionListener(new SelectionListener<ButtonEvent>() {

			@Override
			public void componentSelected(ButtonEvent ce) {
				if (typeCombo.isValid()) {
					addNewTransaction(typeCombo.getValue().getValue());
					box.hide();
				}
			}

		});
		box.getButtonById(Dialog.CANCEL).addSelectionListener(new SelectionListener<ButtonEvent>() {

			@Override
			public void componentSelected(ButtonEvent ce) {
				box.hide();
			}
		});
		box.show();
	}

	/** The new transaction used during the add operation to hold the current, 
	 * so we don't create multiple dirty transactions. */
	private BeanModel newTransaction = null;

	/**
	 * Adds the new transaction.
	 *
	 * @param value the value
	 */
	private void addNewTransaction(TransactionType value) {
		if (newTransaction != null) {
			newTransaction.set("type", value);
			transactionGrid.getSelectionModel().select(newTransaction, false);
			transactionDetailsFormBindings.bind(newTransaction);
			descriptionField.focus();
		} else {
			Transaction t = new Transaction();
			t.setDate(new Date());
			t.setDescription("");
			t.setAmount(0.0d);
			t.setType(value);
			newTransaction = BMF.getTransactionFactory().createModel(t);
			transactionStore.add(newTransaction);
			Record r = transactionStore.getRecord(newTransaction);
			r.set("description", "New Transaction");
			r.set("date", new Date());
			r.set("type", value);
			transactionGrid.getSelectionModel().select(newTransaction, false);
			// enable needs to be after setting the selection ^
			enableTransactionDetailsForm();
			descriptionField.focus();
			newTransaction = null;
		}

	}

	/**
	 * Enable transaction details form.
	 */
	private void enableTransactionDetailsForm() {
		descriptionField.enable();
		dateField.enable();
		amountField.enable();
		if (selectedTransaction.getType().equals(TransactionType.Categorized)) {
			categoryComboBox.enable();
			categoryComboBox.show();
			paycheckComboBox.disable();
			paycheckComboBox.hide();
		} else {
			paycheckComboBox.enable();
			paycheckComboBox.show();
			categoryComboBox.disable();
			categoryComboBox.hide();
		}

	}

	/**
	 * Creates the transaction grid.
	 */
	private void createTransactionGrid() {
		// GWT.log("Creating grid with " + transactionStore.getCount() +
		// " rows");
		// GWT.log("1st row is: " + transactionStore.getAt(1));
		List<ColumnConfig> columns = createTransactionGridColumns();
		ColumnModel cm = new ColumnModel(columns);

		transactionGrid = new Grid<BeanModel>(transactionStore, cm);
		transactionGrid.getView().setEmptyText("No Transactions Defined");
		transactionGrid.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
		transactionGrid.getSelectionModel().addListener(Events.SelectionChange,
				new Listener<SelectionChangedEvent<BeanModel>>() {
					public void handleEvent(SelectionChangedEvent<BeanModel> be) {
						if (be.getSelection().size() > 0) {
							handleRowSelected(be);
						} else {
							handleSelectionCleared();
						}
					}

				});
		transactionGrid.getView().setForceFit(true);
		transactionGrid.setBorders(true);
	}

	/**
	 * Handle row selected.
	 *
	 * @param be the be
	 */
	private void handleRowSelected(SelectionChangedEvent<BeanModel> be) {
		// GWT.log("selection changed");
		selectedTransaction = (Transaction) be.getSelection().get(0).getBean();
		if (selectedTransaction.getType() == TransactionType.Paycheck) {

			if (selectedTransaction.getPaycheckCalc() == null && selectedTransaction.getId() != 0
					&& selectedTransaction.getAssociationName() != null) {
				// paycheck calc has been removed
				MessageBox
						.alert(
								"Old Paycheck Calculator Warning",
								"This transaction is associated with a deleted paycheck.  "
										+ "If you select a new paycheck calculator and commit, you will not be able to reassign "
										+ "this transaction to the previous value.", null);
			}
		}
		removeTransactionsButton.enable();
		enableTransactionDetailsForm();
		transactionDetailsFormBindings.bind((ModelData) be.getSelection().get(0));
	}

	/**
	 * Handle selection cleared.
	 */
	private void handleSelectionCleared() {
		transactionDetailsFormBindings.unbind();
		disableTransactionForm();
		removeTransactionsButton.disable();
	}

	/**
	 * Creates the transaction form.
	 */
	private void createTransactionForm() {
		transactionForm = new FormPanel();
		transactionForm.setHeaderVisible(false);

		dateField = new DateField();
		dateField.setName("date");
		dateField.setFieldLabel("Date");
		dateField.setAllowBlank(false);
		dateField.setAutoValidate(true);
		dateField.getPropertyEditor().setFormat(DateTimeFormat.getFormat("MM/dd/y"));
		transactionForm.add(dateField);

		descriptionField = new TextField<String>();
		descriptionField.setName("description");
		descriptionField.setFieldLabel("Description");
		descriptionField.setAllowBlank(false);
		descriptionField.setMaxLength(32);
		descriptionField.setAutoValidate(true);
		descriptionField.setFireChangeEventOnSetValue(true);
		transactionForm.add(descriptionField);

		amountField = new NumberField();
		amountField.setName("amount");
		amountField.setFieldLabel("Amount");
		amountField.setAllowBlank(false);
		amountField.setAllowNegative(true);
		amountField.setAutoValidate(true);
		amountField.setFormat(NumberFormatter.CURRENCY_NUMBER_FORMAT);
		transactionForm.add(amountField);

		categoryComboBox = new ComboBox<BeanModel>();
		categoryComboBox.setStore(categoriesStore);
		categoryComboBox.setFieldLabel("Category");
		categoryComboBox.setForceSelection(false);
		categoryComboBox.setAllowBlank(true);
		categoryComboBox.setEditable(false);
		categoryComboBox.setName("category");
		categoryComboBox.setDisplayField("name");
		categoryComboBox.setTriggerAction(TriggerAction.ALL);
		categoryComboBox.setFireChangeEventOnSetValue(true);
		categoryComboBox.addListener(Events.Change, new Listener<FieldEvent>() {

			@Override
			public void handleEvent(FieldEvent be) {
				if (transactionGrid.getSelectionModel() != null) {
					BeanModel bm = transactionGrid.getSelectionModel().getSelectedItem();
					if (be.getValue() != null && bm != null && bm.get("type") == TransactionType.Categorized) {
						// amountField.setMinValue(new Double(0));
						Record r = transactionStore.getRecord(bm);
						BeanModel categoryBeanModel = (BeanModel) be.getValue();
						Category c = (Category) categoryBeanModel.getBean();
						r.set("associationName", c.getName());
					}
				}
			}
		});
		transactionForm.add(categoryComboBox);

		paycheckComboBox = new ComboBox<PaycheckCalculator>();
		paycheckComboBox.setStore(paycheckStore);
		paycheckComboBox.setFieldLabel("Paycheck Calculator");
		paycheckComboBox.setForceSelection(false);
		paycheckComboBox.setAllowBlank(true);
		paycheckComboBox.setEditable(false);
		paycheckComboBox.setName("paycheckCalc");
		paycheckComboBox.setDisplayField("name");
		paycheckComboBox.setTriggerAction(TriggerAction.ALL);
		paycheckComboBox.setFireChangeEventOnSetValue(true);
		paycheckComboBox.addListener(Events.Change, new Listener<FieldEvent>() {

			@Override
			public void handleEvent(FieldEvent be) {
				if (transactionGrid.getSelectionModel() != null) {
					BeanModel bm = transactionGrid.getSelectionModel().getSelectedItem();
					if (be.getValue() != null && bm != null && bm.get("type") == TransactionType.Paycheck) {
						Record r = transactionStore.getRecord(bm);
						PaycheckCalculator pc = (PaycheckCalculator) be.getValue();
						if ((Double) bm.get("amount") == 0) {
							// means the user hasn't already changed the amount
							// value
							Double amt = new Double(pc.getEstimatedAmt());
							r.set("amount", amt);
						}
						r.set("associationName", pc.getName());
					}
				}
			}
		});
		transactionForm.add(paycheckComboBox);

		transactionDetailsFormBindings = new FormBinding(transactionForm);
		FieldBinding categoryComboFieldBinding = new FieldBinding(categoryComboBox, "category");
		categoryComboFieldBinding.setConverter(new Converter() {

			@Override
			public Object convertFieldValue(Object value) {
				// Converts the field's value before being set on the model.
				// //after add, also onblur
				BeanModel model = (BeanModel) value;
				return model.getBean();
			}

			@Override
			public Object convertModelValue(Object value) {
				// TODO handle the case where we're rejecting changes and it's
				// null
				return value;
			}

		});
		transactionDetailsFormBindings.addFieldBinding(categoryComboFieldBinding);

		FieldBinding paycheckComboFieldBinding = new FieldBinding(paycheckComboBox, "paycheckCalc");
		paycheckComboFieldBinding.setConverter(new Converter() {

			@Override
			public Object convertFieldValue(Object value) {
				// Converts the field's value before being set on the model.
				// //after add, also onblur
				return value;
			}

			@Override
			public Object convertModelValue(Object value) {
				// Converts the model's value before being set on the field.
				// //on add, fires
				return value;
			}

		});
		transactionDetailsFormBindings.addFieldBinding(paycheckComboFieldBinding);
		transactionDetailsFormBindings.autoBind();
		transactionDetailsFormBindings.setStore(transactionGrid.getStore());
		disableTransactionForm();
	}

	/**
	 * Disable transaction form.
	 */
	private void disableTransactionForm() {
		descriptionField.disable();
		dateField.disable();
		amountField.disable();
		categoryComboBox.disable();
		paycheckComboBox.disable();
	}

	/**
	 * Initialize stores.
	 *
	 * @param data the transaction data
	 */
	private void initializeStores(TransactionData data) {
		transactionStore = new ListStore<BeanModel>();
		transactionStore.setMonitorChanges(true);
		transactionStore.addStoreListener(new StoreListener<BeanModel>() {
			@Override
			public void storeUpdate(StoreEvent<BeanModel> se) {
				if (se.getOperation() != null && se.getOperation().equals(Record.RecordUpdate.COMMIT)) {
					doCommit(se);
				}
			}
		});

		List<BeanModel> transactions = BMF.getTransactionFactory().createModel(data.getTransactions());

		transactionStore.add(transactions);

		categoriesStore = new ListStore<BeanModel>();
		List<BeanModel> categories = BMF.getCategoryFactory().createModel(data.getAllCategories());
		categoriesStore.add(categories);

		// PaycheckCalculators extend TreeBaseModel and don't need a Bean Model
		// Factory
		paycheckStore = new ListStore<PaycheckCalculator>();
		paycheckStore.add(data.getAllPaycheckCalculators());

	}

	/** The batch commit. */
	private List<Transaction> batchCommit = new ArrayList<Transaction>();

	/**
	 * Performs a batch commit of all modified records.
	 *
	 * @param se the store event
	 */
	public void doCommit(StoreEvent se) {
		BeanModel bean = (BeanModel) se.getModel();
		batchCommit.add((Transaction) bean.getBean());
		if (se.getStore().getModifiedRecords().size() == 0) {
			// call the batchService
			fireEvent(new AppEvent(AppEvents.TransactionChangesCommitted, batchCommit));
			// clear the batch list for next time.
			batchCommit = new ArrayList<Transaction>();
		}

	}

	/**
	 * Creates the transaction grid columns.
	 *
	 * @return the list
	 */
	private List<ColumnConfig> createTransactionGridColumns() {
		List<ColumnConfig> configs = new ArrayList<ColumnConfig>();

		dateColumn = new ColumnConfig("date", "Date", 45);
		DateField dateField = new DateField();
		dateField.getPropertyEditor().setFormat(DateTimeFormat.getFormat("MM/dd/y"));
		dateColumn.setEditor(new CellEditor(dateField));
		dateColumn.setDateTimeFormat(DateTimeFormat.getMediumDateFormat());
		configs.add(dateColumn);

		descriptionColumn = new ColumnConfig("description", "Description", 150);
		TextField<String> text = new TextField<String>();
		text.setAllowBlank(false);
		descriptionColumn.setEditor(new CellEditor(text));
		configs.add(descriptionColumn);

		amountColumn = new ColumnConfig("amount", "Amount", 40);
		amountColumn.setAlignment(HorizontalAlignment.RIGHT);
		amountColumn.setNumberFormat(NumberFormatter.CURRENCY_NUMBER_FORMAT);
		amountColumn.setEditor(new CellEditor(new NumberField()));
		configs.add(amountColumn);

		ColumnConfig typeColumn = new ColumnConfig("type", "Type", 45);
		configs.add(typeColumn);

		ColumnConfig associationNameColumn = new ColumnConfig("associationName", "Category/Paycheck", 80);
		configs.add(associationNameColumn);

		return configs;
	}

	/* (non-Javadoc)
	 * @see com.extjs.gxt.ui.client.mvc.View#handleEvent(com.extjs.gxt.ui.client.mvc.AppEvent)
	 */
	@Override
	protected void handleEvent(AppEvent event) {
		if (event.getType() == AppEvents.Init) {
			// GWT.log("TransactionJournalView handling Init");
			initUI(event);
		}
		if (event.getType() == AppEvents.TransactionChangesCommitted) {
			updateStoreWithUpdateInfo(event);
			GWT.log("sending refresh transactions event");
			Dispatcher.get().dispatch(AppEvents.RefreshTransaction);
		}
		if (event.getType() == AppEvents.RefreshCategory) {
			GWT.log("RefreshCategory recieved in editor view");
			List<Category> categories = event.getData();
			List<BeanModel> categoryModels = BMF.getCategoryFactory().createModel(categories);
			categoriesStore.removeAll();
			categoriesStore.add(categoryModels);

			dispatchRefreshTransactionsEvent();
		}
		if (event.getType() == AppEvents.RefreshPaycheck) {
			GWT.log("RefreshPaycheck recieved in editor view");
			List<PaycheckCalculator> paychecks = event.getData();
			paycheckStore.removeAll();
			paycheckStore.add(paychecks);

			dispatchRefreshTransactionsEvent();
		}
	}

	/**
	 * Dispatch refresh transactions event.
	 */
	private void dispatchRefreshTransactionsEvent() {
		AppEvent e = new AppEvent(AppEvents.TransactionChangesCommitted);
		GWT.log("Firing TransactionChangesCommitted event with null transactions");
		fireEvent(e);
	}

	/**
	 * Update store with updated {@link Transaction} info after an add/update.
	 *
	 * @param event the event
	 */
	private void updateStoreWithUpdateInfo(AppEvent event) {
		List<Transaction> updates = (List<Transaction>) event.getData();
		transactionStore.removeAll();
		transactionStore.add(BMF.getTransactionFactory().createModel(updates));
	}

}
